package task;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Map;

public abstract class DbTask extends Task implements IDbTask {

	private Connection conn;
	protected DbType dbType;
	
	public Connection conn() { return conn; }
	@Override
	public void setConnection(Connection conn) {
		this.conn = conn;
		if (conn != null) {
			setDbType();
		}
	}
	@Override
	public void run(Map<String, String> propMap) {
		try {
			doRun(propMap);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	protected void doRun(Map<String, String> propMap) throws SQLException {
	}
	public String[] getTablesInSchema(String schema) throws SQLException {
		switch (dbType) {
		case ORACLE:
			return getTablesInOracleSchema(schema);
		case POSTGRES:
			return getTablesInDbSchema(schema);
		}
		return null;
	}
    private String[] getTablesInDbSchema(String schema) throws SQLException {
    	String[] types = { "TABLE" };
    	ResultSet rs = conn.getMetaData().getTables(null, schema, null, types);
		ArrayList<String> list = new ArrayList<String>();
		while (rs.next()) {
			list.add(rs.getString(3));
		}
		rs.close();
		return list.toArray(new String[0]);
    }
	private String[] getTablesInOracleSchema(String schema) throws SQLException {
		String sql = "select table_name from all_tables where owner=?";
		PreparedStatement stmt = conn.prepareStatement(sql);
		stmt.setString(1, schema);
		ResultSet rs = stmt.executeQuery();
		ArrayList<String> list = new ArrayList<String>();
		while (rs.next()) {
			list.add(rs.getString(1));
		}
		rs.close();
		stmt.close();
		return list.toArray(new String[0]);
	}
	private void setDbType() {
		try {
			dbType = DbType.getDbType(conn.getMetaData().getDatabaseProductName().toLowerCase());
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	public enum DbType {
		ORACLE {
			@Override
			public String getTrue() {
				return "1";
			}
			@Override
			public String getFalse() {
				return "0";
			}
		}, POSTGRES {
			@Override
			public String getTrue() {
				return "true";
			}
			@Override
			public String getFalse() {
				return "false";
			}
		};

		public static DbType getDbType(String typeName) {
			if (typeName.contains("oracle")) return ORACLE;
			return POSTGRES;
		}			
		public abstract String getTrue();
		public abstract String getFalse();
	}
	public String getTrue() { return dbType.getTrue(); }
	public String getFalse() { return dbType.getFalse(); }
	
	public abstract class Traverser {
		public Traverser(String sql) throws SQLException {
			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery(sql);
			while (rs.next()) {
				processRow(rs);
			}
			rs.close();
			stmt.close();
		}
		protected abstract void processRow(ResultSet rs) throws SQLException;
	}
}
